﻿using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Client.AndroiD
{
    [Service] // !!!! 坑 注意要加上
    public class QRCodeCreatorConnectService : Service
    {
        static readonly string TAG = typeof(QRCodeCreatorConnectService).FullName;

        public const string ACTION_START_SERVICE = "QRCodeCreatorConnectService.START_SERVICE";

        System.ComponentModel.BackgroundWorker mBgWorker { get; set; }

        Util.Web.MyTcpClient mMyTcpClient { get; set; }

        public override void OnCreate()
        {
            base.OnCreate();
        }

        public override IBinder OnBind(Intent intent)
        {
            return null;
        }

        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            switch (intent.Action)
            {
                case ACTION_START_SERVICE:
                    start();
                    break;
            }

            return StartCommandResult.Sticky;
        }

        void start()
        {
            if (mBgWorker != null && mBgWorker.IsBusy == true)
            {
                Log.Info(TAG, "OnStartCommand: The service is already running.");
                return;
            }

            mBgWorker = new System.ComponentModel.BackgroundWorker();
            mBgWorker.DoWork += (bgSender, bgArgs) =>
            {
                if (mMyTcpClient != null)
                {
                    // 连接中
                    return;
                }

                if (string.IsNullOrEmpty(StaticInfo.QRCodeCreatorConnect.IP))
                {
                    return;
                }

                if (string.IsNullOrEmpty(StaticInfo.QRCodeCreatorConnect.Port))
                {
                    return;
                }

                string ip = StaticInfo.QRCodeCreatorConnect.IP;
                string port = StaticInfo.QRCodeCreatorConnect.Port;

                mMyTcpClient = new Util.Web.MyTcpClient(isStandardReceive: true); // 已升级到 Uitl.HowesDOMO 1.0.19 -- 改用 StandardReceive
                mMyTcpClient.ReceiveText += new System.EventHandler<Util.Web.TcpXxxEventArgs>(tcpClient_ReceiveText);
                mMyTcpClient.StatusChange += new EventHandler<Util.Web.TcpXxxStatusChangeEventArgs>(tcpClient_StatusChange);

                mMyTcpClient.StartTimeout = TimeSpan.FromSeconds(10); // 设置连接超时

                // 遇到的坑 在 Release 版本中执行到 Start 时报错 ( 奇怪的是在 Debug 中能正常运行 )
                // System.Net.Sockets.SocketException : Access denied
                // 
                // 解决方法 在权限中增加 <uses-permission android:name="android.permission.INTERNET"/>
                mMyTcpClient.Start(ip, port);

                Log.Info(TAG, "OnStartCommand: The service is starting.");
            };

            mBgWorker.RunWorkerAsync(new object[] { });
        }

        void stop()
        {
            Log.Info(TAG, "OnStartCommand: The service is stopping.");

            if (mMyTcpClient == null)
            {
                return;
            }

            mMyTcpClient.ReceiveText -= new System.EventHandler<Util.Web.TcpXxxEventArgs>(tcpClient_ReceiveText);
            mMyTcpClient.Stop();

            mMyTcpClient = null;
        }

        public override void OnDestroy()
        {
            Log.Info(TAG, "OnDestroy: The started service is shutting down.");

            stop();

            var notificationManager = (NotificationManager)GetSystemService(NotificationService);
            notificationManager.Cancel(SERVICE_RUNNING_NOTIFICATION_ID);

            base.OnDestroy();
        }

        #region 通知栏

        public const int SERVICE_RUNNING_NOTIFICATION_ID = 48002;

        string createNotificationChannel(string channnelId, string channnelName)
        {
            NotificationChannel chan = new NotificationChannel(channnelId, channnelName, NotificationImportance.None);
            // chan.LightColor = 30000; // 在安卓10上设置颜色好像没没有什么效果 -- LED 颜色灯
            chan.LockscreenVisibility = NotificationVisibility.Private;
            NotificationManager service = (NotificationManager)GetSystemService(NotificationService);
            service.CreateNotificationChannel(chan);
            return channnelId;
        }

        void RegisterForegroundService()
        {
            Notification.Builder builder = null;

            if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
            {
                // !!!! 遇到的坑 小米5s Plus (安卓8/MIUI 11.0.2) 需要手动允许通知 --> 允许 FakeScanner 连接PC 的通知
                string channelId = createNotificationChannel(channnelId: "FakeScanner_ConnectPC", channnelName: "FakeScanner 连接PC");
                builder = new Notification.Builder(this, channelId);
            }
            else
            {
                // 修复 android 5 运行异常
                // 运行带 2 个参数的 Builder 会报错
                builder = new Notification.Builder(this);
            }

            Notification notification = builder
                .SetContentTitle(Resources.GetString(Resource.String.app_name))
                .SetContentText($"正在接收 {StaticInfo.QRCodeCreatorConnect.IP}:{StaticInfo.QRCodeCreatorConnect.Port} 信息")
                .SetSmallIcon(Resource.Drawable.pc)
                .SetContentIntent(BuildIntentToShowMainActivity())
                .SetOngoing(true) // 表示它为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)
                // .SetProgress(100, 90, false) // max:进度条最大数值  、progress:当前进度、indeterminate:表示进度是否不确定，true为不确定
                                             // 一个通知最多可以提供三个操作按钮，让用户可以快速响应，例如暂停提醒，甚或回复短信。
                                             //.AddAction(BuildRestartTimerAction())
                                             //.AddAction(BuildStopServiceAction())
                .Build();

            // Enlist this instance of the service as a foreground service
            StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
        }

        /// <summary>
        /// Builds a PendingIntent that will display the main activity of the app. This is used when the 
        /// user taps on the notification; it will take them to the main activity of the app.
        /// </summary>
        /// <returns>The content intent.</returns>
        PendingIntent BuildIntentToShowMainActivity()
        {
            // 在 MainActivity 的 Activity 标签中设置 LaunchMode = Android.Content.PM.LaunchMode.SingleInstance 来保证返回到已打开的 Activity
            // 还要在 MainActivity 中禁止 Back 返回键对 Activity 的销毁
            var notificationIntent = new Intent(this, typeof(MainActivity));
            notificationIntent.SetAction("main");
            notificationIntent.SetFlags(ActivityFlags.SingleTop | ActivityFlags.ClearTask); // 重新打开前需要进入 Destory() 销毁 MessageCenter
            notificationIntent.SetFlags(ActivityFlags.ReceiverVisibleToInstantApps);
            notificationIntent.PutExtra(MainActivity.SERVICE_STARTED_KEY, true);

            #region PendingIntentFlags 解释
            // FLAG_ONE_SHOT        表示返回的PendingIntent仅能执行一次，执行完后自动取消
            // FLAG_NO_CREATE       表示如果描述的PendingIntent不存在，并不创建相应的PendingIntent，而是返回NULL
            // FLAG_CANCEL_CURRENT  表示相应的PendingIntent已经存在，则取消前者，然后创建新的PendingIntent，这个有利于数据保持为最新的，可以用于即时通信的通信场景
            // FLAG_UPDATE_CURRENT  表示更新的PendingIntent
            #endregion

            var pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, PendingIntentFlags.UpdateCurrent);
            return pendingIntent;
        }

        #endregion        

        void tcpClient_StatusChange(object sender, Util.Web.TcpXxxStatusChangeEventArgs args)
        {
            System.Diagnostics.Debug.WriteLine(args.ConsoleMsg);

            var path = System.IO.Path.Combine(this.GetExternalFilesDir(string.Empty).Path, "Log.txt");
            if (System.IO.File.Exists(path))
            {
                var msg = $"\r\n{args.EntryTime} - {args.ConsoleMsgType}\r\n{args.ConsoleMsg}";
                System.IO.File.AppendAllText(path, msg);
            }
            else
            {
                var msg = $"{args.EntryTime} - {args.ConsoleMsgType}\r\n{args.ConsoleMsg}";
                System.IO.File.WriteAllText(path, msg);
            }

            if (args.ConsoleMsgType == Util.UIModel.ConsoleMsgType.ERROR)
            {
                stop(); // 无法连接服务器
                return;
            }

            // 例子: MyTcpClient 连接服务器 192.168.137.1:48001 成功。
            if (args.ConsoleMsg.Contains("MyTcpClient 连接服务器") == true && args.ConsoleMsg.Contains("成功") == true) 
            {
                RegisterForegroundService();

                // 成功连接 保存 IP 和 Port 到 SecureStorage 中
                Xamarin.Essentials.SecureStorage.SetAsync(MainActivity.k_IP, StaticInfo.QRCodeCreatorConnect.IP);
                Xamarin.Essentials.SecureStorage.SetAsync(MainActivity.k_Port, StaticInfo.QRCodeCreatorConnect.Port);

                return;
            }
            else if (args.ConsoleMsg.Contains("监听服务已停止") == true)
            {
                StopSelf(); // 关闭自身(关闭服务)
                return;
            }
        }

        void tcpClient_ReceiveText(object sender, Util.Web.TcpXxxEventArgs args)
        {
            MainActivity.RunZhuanFaGuangBo(args.Msg);
        }
    }
}